package com.suitbim.commandserver.commandserver.manage;


import com.google.gson.Gson;
import com.suitbim.commandserver.commandserver.client.ifs.CommandClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;


/**
 * 调度的过程是这样的，有client的资源池，client资源用尽就不进行处理，但是所有的任务可以预先开始下载，如果有client空闲，就在队列中检索可以处理的任务
 * 队列遵循左出右进原则
 */
@Component
public class CommandManage {

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private Gson gson;

    @Value("${redis-message-queue.command-queue}")
    private String messageQueueName;

    @Value("${redis-message-queue.revit-command}")
    private String revitQueueName;

    @Value("${redis-message-queue.navisworks-command}")
    private String navisworksQueueName;

    @Value("${client.enable.main-client}")
    private boolean mainClient;

    Logger log = LoggerFactory.getLogger(this.getClass());

    public void init() {
        if (mainClient) {
            Runnable main = mainThread();
            threadPoolExecutor.submit(main);
            System.out.println("main client start");
        }
    }

    /**
     * 这个个主线程主要接受命令以及进行预处理
     *
     * @return
     */
    private Runnable mainThread() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    List<Object> objects;
                    try {
                        objects = redisTemplate.executePipelined(new RedisCallback<Object>() {
                            @Override
                            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                                //队列没有元素会阻塞操作，直到队列获取新的元素或超时，设置为0是永久阻塞
                                return connection.bLPop(360000, messageQueueName.getBytes());
                            }
                        });
                    } catch (Exception e) {
                        continue;
                    }

                    String json = (String) ((List) objects.get(0)).get(1);

                    log.info("receive command:" + json);

                    CommandClient.Command command = gson.fromJson(json, CommandClient.Command.class);

                    try {

                        String client = "";
                        if (isRevitFile(command.getUrl())) {
                            writeToMessageQueue(revitQueueName, json, false);
                            client = "revit";
                        } else {
                            writeToMessageQueue(navisworksQueueName, json, false);
                            client = "naviswork";
                        }
                        log.info("send " + client + " client command");

                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        log.info("handle command finish");
                    }
                }
            }
        };
        return runnable;
    }

    private boolean isRevitFile(String url) {
        return url.toLowerCase().trim().endsWith("rvt");
    }

    private void writeToMessageQueue(String key, String text, boolean publish) {
        if (publish) redisTemplate.convertAndSend(key, text);
        else redisTemplate.opsForList().rightPush(key, text);
    }

}

